package com.itfreer.password;

import java.io.UnsupportedEncodingException;
import java.nio.charset.Charset;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.HashMap;
import java.util.Map;

import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.core.Context;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Component;

import com.itfreer.sso.authentication.utils.PasswordEncoder;
@Component("userPasswordEncoder")
@Path("/userPasswordEncoder/")
public class UserPasswordEncoder  implements PasswordEncoder {
	
    private static final char[] HEX_DIGITS = {'0', '1', '2', '3', '4', '5', '6', '7', '8',
            '9', 'a', 'b', 'c', 'd', 'e', 'f'};
    private static final int HEX_RIGHT_SHIFT_COEFFICIENT = 4;
	private static final int HEX_HIGH_BITS_BITWISE_FLAG = 0x0f;

	private static final Logger LOGGER = LoggerFactory.getLogger(UserPasswordEncoder.class);
	
    private final String encodingAlgorithm;

    private String characterEncoding;

    public UserPasswordEncoder(){
    	this.encodingAlgorithm = "";
    }

    /**
     * Instantiates a new default password encoder.
     *
     * @param encodingAlgorithm the encoding algorithm
     */
    public UserPasswordEncoder(final String encodingAlgorithm) {
        this.encodingAlgorithm = encodingAlgorithm;
    }
	
  	@Override
    public String encode(final String password) {
        if (password == null) {
            return null;
        }
        
        try {
			return encryptData(password,key,IV);
		} catch (Exception e) {
//			throw new RuntimeException(e);
			e.printStackTrace();
			return password;
			// TODO Auto-generated catch block
			
		}

        /*if (StringUtils.isBlank(this.encodingAlgorithm)) {
            LOGGER.warn("No encoding algorithm is defined. Password cannot be encoded; Returning null");
            return null;
        }

        try {
            final MessageDigest messageDigest = MessageDigest.getInstance(this.encodingAlgorithm);

            final String encodingCharToUse = StringUtils.isNotBlank(this.characterEncoding)
                    ? this.characterEncoding : Charset.defaultCharset().name();

            LOGGER.warn("Using {} as the character encoding algorithm to update the digest", encodingCharToUse);
            messageDigest.update(password.getBytes(encodingCharToUse));

            final byte[] digest = messageDigest.digest();

            return getFormattedText(digest);
        } catch (final NoSuchAlgorithmException e) {
            throw new SecurityException(e);
        } catch (final UnsupportedEncodingException e) {
            throw new RuntimeException(e);
        }*/
    }
  	
  	@POST
	@Path("decode")
  	public Map<String, Object> decode(@Context HttpServletRequest request, @Context HttpServletResponse response) {
  		String easusername = request.getParameter("username");
  		String easpassword = request.getParameter("password");
  		Map<String, Object> result = new HashMap<String, Object>();
  		if (easusername == null || easpassword == null) {
  			return null;
  		}
        try {
        	String username = decryptData(easusername,key,IV);
        	String password = decryptData(easpassword,key,IV);
        	result.put("username", username);
        	result.put("password", password);
			return result;
		} catch (Exception e) {
			e.printStackTrace();
			return result;
//			 throw new RuntimeException(e);
			// TODO Auto-generated catch block
			
		}
    }

    /**
     * Takes the raw bytes from the digest and formats them correct.
     *
     * @param bytes the raw bytes from the digest.
     * @return the formatted bytes.
     */
    private static String getFormattedText(final byte[] bytes) {
        final StringBuilder buf = new StringBuilder(bytes.length * 2);

        for (int j = 0; j < bytes.length; j++) {
            buf.append(HEX_DIGITS[(bytes[j] >> HEX_RIGHT_SHIFT_COEFFICIENT) & HEX_HIGH_BITS_BITWISE_FLAG]);
            buf.append(HEX_DIGITS[bytes[j] & HEX_HIGH_BITS_BITWISE_FLAG]);
        }
        return buf.toString();
    }

    public void setCharacterEncoding(final String characterEncoding) {
        this.characterEncoding = characterEncoding;
    }
    
    public final static String key="skywayr&d/administrator\\tianheng";
    
    public final static String IV="skywayRD-maolan!";
    
    /**
     * aes 解密
     *
     * @param data
     *            密文
     * @return
     */
    public static String decryptData(String data, String key, String IV) throws Exception {
        try {
            byte[] encrypted1 = Base64.decodeBase64(data.getBytes("UTF-8"));
            Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
            SecretKeySpec keyspec = new SecretKeySpec(key.getBytes("UTF-8"), "AES");
            IvParameterSpec ivspec = new IvParameterSpec(IV.getBytes("UTF-8"));
            cipher.init(Cipher.DECRYPT_MODE, keyspec, ivspec);
            byte[] original = cipher.doFinal(encrypted1);
            String originalString = new String(original, "UTF-8");
            return originalString;
        } catch (Exception e) {
//            throw e;
        	e.printStackTrace();
            return data;
        }
    }
    
    /**
     * aes 加密
     *
     * @param data
     * @return
     */
    public static String encryptData(String data, String key, String IV) throws Exception {
        try {
            Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
            byte[] dataBytes = data.getBytes("UTF-8");
            int plaintextLength = dataBytes.length;
            byte[] plaintext = new byte[plaintextLength];
            System.arraycopy(dataBytes, 0, plaintext, 0, dataBytes.length);
            SecretKeySpec keyspec = new SecretKeySpec(key.getBytes("UTF-8"), "AES");
            IvParameterSpec ivspec = new IvParameterSpec(IV.getBytes("UTF-8"));
            cipher.init(Cipher.ENCRYPT_MODE, keyspec, ivspec);
            byte[] encrypted = cipher.doFinal(plaintext);
            return new String(Base64.encodeBase64(encrypted));
        } catch (Exception e) {
            throw e;
        }
 
    }

}
